﻿Imports OpenTK
Imports OpenTK.Graphics
Imports OpenTK.Graphics.OpenGL4

Class TriangleRegionDivision
    Public programTRR As Integer
    Public programTSD As Integer

    Dim triangles() As Single
    Public Sub New(triangledata() As Single)
        triangles = triangledata
        programTRR = LoadTRRShader()
        programTSD = LoadTSDShader()
    End Sub

    Private Function LoadTRRShader() As Integer
        Dim TRR = GL.CreateProgram()
        Dim cshader = GL.CreateShader(ShaderType.ComputeShader)
        GL.ShaderSource(cshader, System.IO.File.ReadAllText("shader\TriangleReflectionRegion.glcs"))
        GL.CompileShader(cshader)
        Dim csLog As String = GL.GetShaderInfoLog(cshader)
        Console.WriteLine(csLog)
        If csLog.Contains("error") Then Throw New Exception(csLog)
        GL.AttachShader(TRR, cshader)
        GL.LinkProgram(TRR)
        Dim programLog As String = GL.GetProgramInfoLog(TRR)
        Console.WriteLine(programLog)
        If programLog.Contains("error") Then Throw New Exception(programLog)
        Return TRR
    End Function

    Private Function LoadTSDShader() As Integer
        Dim TSD = GL.CreateProgram()
        Dim cshader = GL.CreateShader(ShaderType.ComputeShader)
        GL.ShaderSource(cshader, System.IO.File.ReadAllText("shader\TriangleShadowDetection.glcs"))
        GL.CompileShader(cshader)
        Dim csLog As String = GL.GetShaderInfoLog(cshader)
        Console.WriteLine(csLog)
        If csLog.Contains("error") Then Throw New Exception(csLog)
        GL.AttachShader(TSD, cshader)
        GL.LinkProgram(TSD)
        Dim programLog As String = GL.GetProgramInfoLog(TSD)
        Console.WriteLine(programLog)
        If programLog.Contains("error") Then Throw New Exception(programLog)
        Return TSD
    End Function

    Public img As Integer
    Private triangleCount As Integer
    Dim outTex() As Single
    Public Sub InitImage(nTriangle As Integer)
        'allocate
        triangleCount = nTriangle
        img = GL.GenTexture()
        GL.BindTexture(TextureTarget.Texture2D, img)
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, TextureMagFilter.Nearest)
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, TextureMinFilter.Nearest)
        'GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba32f, nTriangle, nTriangle, 0, PixelFormat.Rgba, PixelType.Float, outTex)
        GL.TexStorage2D(TextureTarget2d.Texture2D, 1, SizedInternalFormat.Rgba32f, nTriangle, nTriangle) ' levels should be greater than 0. different form TexImage2D's level parameter
        GL.BindTexture(TextureTarget.Texture2D, 0)
    End Sub

    Public Sub ComputeTriangleReflectionRegion(texTriangle As Integer)
        'bind input
        GL.UseProgram(programTRR)
        Dim uInputTriangle = GL.GetUniformLocation(programTRR, "inputTriangle")
        GL.ActiveTexture(TextureUnit.Texture0)
        GL.BindTexture(TextureTarget.TextureBuffer, texTriangle)
        GL.Uniform1(uInputTriangle, 0)

        Dim uTriangleCount = GL.GetUniformLocation(programTRR, "TriangleCount")

        GL.Uniform1(uTriangleCount, triangleCount)
        GL.BindImageTexture(0, img, 0, False, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba32f)

        'compute
        Dim t0 = DateTime.Now
        GL.DispatchCompute(triangleCount, 1, 1)
        GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit)
        GL.Flush()

        'get result
        'outTex = New Single(triangleCount * triangleCount * 4 - 1) {}
        'GL.BindTexture(TextureTarget.Texture2D, img)
        'GL.GetTexImage(TextureTarget.Texture2D, 0, PixelFormat.Rgba, PixelType.Float, outTex)
        'Dim arrReflection(triangleCount - 1) As List(Of Single)
        'Dim max As Integer = 0
        'Dim maxIndex As Integer = -1
        'For i = 0 To triangleCount - 1
        '    Dim size = outTex(i * 4 + 0)
        '    arrReflection(i) = New List(Of Single)
        '    For j = 0 To size - 1
        '        Dim coord = (j + 1) * triangleCount + i
        '        arrReflection(i).Add(outTex(coord * 4 + 0))
        '    Next
        '    If size > max Then
        '        max = size
        '        maxIndex = i
        '    End If
        'Next
        'Console.WriteLine("最大反射三角形数量:" + max.ToString())
    End Sub


    Public Sub ComputeTriangleShadowCasting(texTriangle As Integer)
        'bind input
        GL.UseProgram(programTSD)
        Dim uInputTriangle = GL.GetUniformLocation(programTSD, "inputTriangle")
        GL.ActiveTexture(TextureUnit.Texture0)
        GL.BindTexture(TextureTarget.TextureBuffer, texTriangle)
        GL.Uniform1(uInputTriangle, 0)

        Dim uTriangleCount = GL.GetUniformLocation(programTSD, "TriangleCount")
        GL.Uniform1(uTriangleCount, triangleCount)

        For Each l In Light.LightObjects
            l.UpdateProgramUniform(programTSD)
        Next
        GL.BindImageTexture(0, img, 0, False, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba32f)

        'compute
        GL.DispatchCompute(triangleCount, 1, 1)
        GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit)
        GL.Flush()

        'get result
        'outTex = New Single(triangleCount * triangleCount * 4 - 1) {}
        'GL.BindTexture(TextureTarget.Texture2D, img)
        'GL.GetTexImage(TextureTarget.Texture2D, 0, PixelFormat.Rgba, PixelType.Float, outTex)
        'Dim arrBlocking(triangleCount - 1) As List(Of Single)
        'Dim max As Integer = 0
        'Dim maxIndex As Integer = -1
        'Dim linesize = triangleCount * 4
        'Dim lll = 0
        'For i = 0 To triangleCount - 1
        '    Dim light1count = outTex(i * 4 + 1 + linesize * 1)
        '    If light1count! = 0 Then lll += 1
        '    arrBlocking(i) = New List(Of Single)
        '    For j = 0 To light1count - 1
        '        Dim coord = (j + 2) * triangleCount + i
        '        arrBlocking(i).Add(outTex(coord * 4 + 1))
        '    Next
        '    If light1count > max Then
        '        max = light1count
        '        maxIndex = i
        '    End If
        'Next
        'Console.WriteLine("灯光1最大遮挡数量:" + max.ToString())
    End Sub

End Class
